package net.tv90.bfmccore.helper;

import com.tuershen.nbtlibrary.api.NBTTagCompoundApi;
import com.tuershen.nbtlibrary.minecraft.nbt.*;
import net.tv90.bfmccore.BFMCCore;
import org.bitterorange.flansmodslain.FlansModAPI;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.util.*;

import static net.tv90.bfmccore.BFMCCore.PLUGIN_ROOT;
import static net.tv90.bfmccore.BFMCCore.plugin;
import static net.tv90.bfmccore.helper.ItemHelper.idToItem;

public class FlanHelper {

    //储存武器类型的字符串数组
    public static final String[] WeaponType = {
            "AR", "CR", "SMG", "LMG", "HMG", "HG", "DMR", "SR", "SG", "EXP", "ME", "ATW", "BlowTorch",
            "JET", "AA", "MBT", "IFV", "FAC", "Bomber", "Heli", "ScoutHeli", "Mortar", "Transport", "UAV"};
    //储存可获得勤务之星的武器
    public static Set<Material> ServiceStarData = new HashSet<>();
    //储存武器类型对应的中文名称
    public static Map<String, String> WeaponTypeMap = new HashMap<>();
    //把不同的武器进行分类，并储存
    public static Map<String, List<String>> WeaponTypeData = new HashMap<>();

    static {
        WeaponTypeMap.put("AR", "突击步枪");
        WeaponTypeMap.put("CR", "卡宾步枪");
        WeaponTypeMap.put("SMG", "冲锋枪");
        WeaponTypeMap.put("LMG", "轻机枪");
        WeaponTypeMap.put("HMG", "重机枪");
        WeaponTypeMap.put("HG", "手枪");
        WeaponTypeMap.put("DMR", "射手步枪");
        WeaponTypeMap.put("SR", "狙击步枪");
        WeaponTypeMap.put("SG", "霰弹枪");
        WeaponTypeMap.put("EXP", "爆破");
        WeaponTypeMap.put("ME", "近战");
        WeaponTypeMap.put("ATW", "反制载具");
        WeaponTypeMap.put("BlowTorch", "喷灯");
        WeaponTypeMap.put("JET", "战斗机");
        WeaponTypeMap.put("AA", "防空");
        WeaponTypeMap.put("MBT", "坦克");
        WeaponTypeMap.put("IFV", "步战车");
        WeaponTypeMap.put("FAC", "攻击快艇");
        WeaponTypeMap.put("Bomber", "轰炸机");
        WeaponTypeMap.put("Heli", "武装直升机");
        WeaponTypeMap.put("ScoutHeli", "侦察直升机");
        WeaponTypeMap.put("Mortar", "迫击炮");
        WeaponTypeMap.put("Transport", "轻型运输载具");
        WeaponTypeMap.put("UAV", "无人载具");
    }

    public static void loadWeaponTypeData() throws Exception {
        WeaponTypeData.clear();
        for (String value : WeaponType) {
            File file = new File(PLUGIN_ROOT, "/WeaponTypeData/Weapon_" + value + "Data.yml");
            if (!file.exists())
                plugin.saveResource("Weapon_" + value + "Data.yml", false);
            Map<String, List<String>> map = (Map<String, List<String>>) (new Yaml()).loadAs(new FileInputStream(file), Map.class);
            List<String> list = map.get("Data");
            WeaponTypeData.put(value, list);
        }
    }

    /**
     * 获取武器类型
     *
     * @param weapon 武器
     * @return return
     */
    public static String getWeaponType(String weapon) {
        for (String value : WeaponType) {
            List<String> type = WeaponTypeData.get(value);
            if (type != null && type.contains(weapon)) {
                return value;
            }
        }
        return "Unclassified";
    }

    private static void loadServiceStarData() throws Exception {
        File file = new File(PLUGIN_ROOT, "ServiceStarData.yml");
        if (!file.exists())
            plugin.saveResource("ServiceStarData.yml", false);
        ServiceStarData.clear();
        Map<String, List<String>> map = (Map<String, List<String>>) (new Yaml()).loadAs(new FileInputStream(file), Map.class);
        map.get("ServiceStarData").forEach(s -> ServiceStarData.add(Material.valueOf(s)));
    }

    /**
     * 获取某枪械的配件，只包含瞄具、枪口、下挂、附挂
     *
     * @param gun 枪械ItemStack
     * @return 配件List
     */
    public static List<String> getAllAttachment(ItemStack gun) {
        if (gun == null || !gun.getType().name().startsWith("FLANSMOD_")) return new ArrayList<>();
        //第一级tag{第二级attachments{第三级TYPE{id/Count/Damage/tag}}}
        try {
            NBTTagCompoundApi tag = BFMCCore.libraryApi.getCompound(gun);
            if (tag == null) return new ArrayList<>();

            TagCompound<?> attachmentType = tag.getCompound("attachments").getNBTTagCompoundApi();
            List<String> list = new ArrayList<>();

            try {
                TagCompound<?> scopeTag = attachmentType.getCompound("scope");
                list.add(FlansModAPI.nameOfWeapon(idToItem(scopeTag.getShort("id").getShort())).replace("AIR", "金属瞄具"));
            } catch (NullPointerException e) {
                list.add("金属瞄具");
            }

            try {
                TagCompound<?> barrelTag = attachmentType.getCompound("barrel");
                list.add(FlansModAPI.nameOfWeapon(idToItem(barrelTag.getShort("id").getShort())).replace("AIR", "原厂枪管"));
            } catch (NullPointerException e) {
                list.add("原厂枪管");
            }

            try {
                TagCompound<?> gripTag = attachmentType.getCompound("grip");
                list.add(FlansModAPI.nameOfWeapon(idToItem(gripTag.getShort("id").getShort())).replace("AIR", "无下挂"));
            } catch (NullPointerException e) {
                list.add("无下挂");
            }

            try {
                TagCompound<?> gadgetTag = attachmentType.getCompound("gadget");
                list.add(FlansModAPI.nameOfWeapon(idToItem(gadgetTag.getShort("id").getShort())).replace("AIR", "无附挂"));
            } catch (NullPointerException e) {
                list.add("无附挂");
            }

            return list;
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * @param gun        手中武器的ItemStack
     * @param type       配件种类
     * @param attachment 配件英文ID
     * @return 装好配件的武器ItemStack，若配件英文ID不存在，直接返回ItemStack形参
     */
    public static ItemStack setAttachment(ItemStack gun, String type, Material attachment) {
        //第一级tag{第二级attachments{第三级TYPE{id/Count/Damage/tag}}}
        try {
            NBTTagCompoundApi tag = BFMCCore.libraryApi.getCompound(gun);
            NBTTagCompoundApi attachments = tag.getCompound("attachments");
            int attachmentsID = ItemHelper.itemToID(attachment);
            TagCompound attachmentType = attachments.getNBTTagCompoundApi();

            TagCompound tagcompound = new TagCompound<>();
            tagcompound.put("id", new TagShort((short) attachmentsID));
            tagcompound.put("Count", new TagByte((byte) 1));
            tagcompound.put("Damage", new TagShort((short) 0));
            tagcompound.put("tag", new TagCompound<>());

            attachmentType.put(type, tagcompound);

            TagCompound newTag = new TagCompound<>();
            newTag.put("attachments", attachmentType);
            tag.setCompoundMap(newTag);

            return BFMCCore.libraryApi.setCompound(gun, tag);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
        return gun;
    }

    /**
     * @param gun  手中武器的ItemStack
     * @param ammo 弹药英文ID
     * @return 装好弹药的武器ItemStack，若弹药英文ID不存在，直接返回ItemStack形参
     */
    public static ItemStack setAmmo(ItemStack gun, Material ammo) {
        if (gun == null) return null;
        //tag{ammo{0{id-short/Count-byte/Damage-short}}}
        try {
            NBTTagCompoundApi tag = BFMCCore.libraryApi.getCompound(gun);
            int ammoID = ItemHelper.itemToID(ammo);
            TagCompound attachmentTag = tag.getNBTTagCompoundApi();

            TagCompound tagcompound = new TagCompound();
            tagcompound.put("id", new TagShort((short) ammoID));
            tagcompound.put("Count", new TagByte((byte) 1));
            tagcompound.put("Damage", new TagShort((short) 0));

            TagList ammoList = new TagList<>();
            ammoList.add(tagcompound);

            attachmentTag.put("ammo", ammoList);
            attachmentTag.put("secondaryFire", new TagByte((byte) 0));
            attachmentTag.put("Paint", new TagString(""));
            tag.setCompoundMap(attachmentTag);

            return BFMCCore.libraryApi.setCompound(gun, tag);
        } catch (Exception e) {
            System.out.println("Exception");
            e.printStackTrace();
        }
        return gun;
    }

    /**
     * @param gun    手中武器的ItemStack
     * @param ammo   弹药英文ID
     * @param numMag 弹药数量(霰弹枪用)
     * @return 装好弹药的武器ItemStack，若弹药英文ID不存在，直接返回ItemStack形参
     */
    public static ItemStack setAmmo(ItemStack gun, Material ammo, int numMag) {
        if (gun == null) return null;
        //tag{List<ammo-(id-short/Count-byte/Damage-short)>}}
        try {
            NBTTagCompoundApi tag = BFMCCore.libraryApi.getCompound(gun);
            int ammoID = ItemHelper.itemToID(ammo);
            TagCompound attachmentTag = tag.getNBTTagCompoundApi();

            TagCompound tagcompound = new TagCompound();
            tagcompound.put("id", new TagShort((short) ammoID));
            tagcompound.put("Count", new TagByte((byte) 1));
            tagcompound.put("Damage", new TagShort((short) 0));

            TagList ammoList = new TagList<>();
            for (int i = 0; i < numMag; i++) {
                ammoList.add(tagcompound);
            }

            attachmentTag.put("ammo", ammoList);
            attachmentTag.put("secondaryFire", new TagByte((byte) 0));
            attachmentTag.put("Paint", new TagString(""));
            tag.setCompoundMap(attachmentTag);

            return BFMCCore.libraryApi.setCompound(gun, tag);
        } catch (Exception e) {
            System.out.println("Exception");
            e.printStackTrace();
        }
        return gun;
    }

    public static GunState getGunState(ItemStack gun) {
        if (gun == null || !gun.getType().name().contains("FLANSMOD_")) return null;
        NBTTagCompoundApi tag = BFMCCore.libraryApi.getCompound(gun);
        if (tag == null) return null;

        return new GunState();
    }

    public static class GunState {
        private String fireMode;
        private int skinID;
        private int ammoState;

        public String getFireMode() {
            return this.fireMode;
        }

        public int skinID() {
            return this.skinID;
        }

        public int ammoState() {
            return this.ammoState;
        }
    }
}
